home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / corelib / ncbibs.c < prev    next >
Text File  |  1996-07-05  |  21KB  |  809 lines

  1. /*  ncbibs.c
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE                          
  5. *               National Center for Biotechnology Information
  6. *                                                                          
  7. *  This software/database is a "United States Government Work" under the   
  8. *  terms of the United States Copyright Act.  It was written as part of    
  9. *  the author's official duties as a United States Government employee and 
  10. *  thus cannot be copyrighted.  This software/database is freely available 
  11. *  to the public for use. The National Library of Medicine and the U.S.    
  12. *  Government have not placed any restriction on its use or reproduction.  
  13. *                                                                          
  14. *  Although all reasonable efforts have been taken to ensure the accuracy  
  15. *  and reliability of the software and data, the NLM and the U.S.          
  16. *  Government do not and cannot warrant the performance or results that    
  17. *  may be obtained by using this software or data. The NLM and the U.S.    
  18. *  Government disclaim all warranties, express or implied, including       
  19. *  warranties of performance, merchantability or fitness for any particular
  20. *  purpose.                                                                
  21. *                                                                          
  22. *  Please cite the author in any work or product based on this material.   
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:  ncbibs.c
  27. *
  28. * Author:  Jim Ostell
  29. *
  30. * Version Creation Date:  3/4/91
  31. *
  32. * $Revision: 2.7 $
  33. *
  34. * File Description:
  35. *   ByteStore functions
  36. *      NOTE: increasing BS_MAXALLOC will require changing len, and
  37. *            len_avail to Int4 (ncbibs.h)
  38. *
  39. *   This version needs the following enhancements:
  40. *   1) a BSCompact function to pack a fragmented ByteStore
  41. *   2) use made of MIN_BSALLOC to make all allocated space at
  42. *      least MIN_BSALLOC long, so it would be possible to have len_avail
  43. *      bigger than len at internal BSUnits as well as at the end.  This
  44. *      will make insertion and appending of small amounts much more
  45. *      efficient.
  46. *
  47. * Modifications:  
  48. * --------------------------------------------------------------------------
  49. * Date     Name        Description of modification
  50. * -------  ----------  -----------------------------------------------------
  51. * 3/4/91   Kans        Stricter typecasting for GNU C and C++.
  52. * 09-19-91 Schuler     All sizes are expressed as Int4, not Uint4.
  53. * 09-20-91 Schuler     All exported functions are LIBCALL.
  54. * 09-20-91 Schuler     BSGetByte returns EOF on failure.
  55. * 09-20-91 Schuler     BSPutByte(bsp,EOF) truncates bsp at curr. position.
  56. * 04-15-93 Schuler     Changed _cdecl to LIBCALL
  57. *
  58. * ==========================================================================
  59. */
  60.  
  61. #include <ncbi.h>
  62. #include <ncbiwin.h>
  63.  
  64.          /* maximum size allocated for BSUnit.str */
  65. #define MAX_BSALLOC 32700
  66.          /* minimum size block to allocate except on new */
  67. #define MIN_BSALLOC 1024
  68.  
  69. #ifdef MSC_VIRT
  70. extern Nlm_Boolean wrote_to_handle;  /* needed by Microsoft DOS Virtual mem */
  71. #undef MAX_BSALLOC                     /* bad with big blocks */
  72. #define MAX_BSALLOC 10000
  73. #endif
  74.  
  75. /*****************************************************************************
  76. *
  77. *   Pointer Nlm_BSMerge(bsp, dest)
  78. *      if dest == NULL, allocates storage for merge and returns pointer to it
  79. *
  80. *****************************************************************************/
  81. Nlm_VoidPtr LIBCALL  Nlm_BSMerge (Nlm_ByteStorePtr bsp, Nlm_VoidPtr dest)
  82.  
  83. {
  84.     Nlm_BytePtr tmp, from;
  85.     Nlm_BSUnitPtr bsup;
  86.     Nlm_Int4 size;
  87.  
  88.     if (bsp == NULL)
  89.         return NULL;
  90.  
  91.     size = Nlm_BSLen(bsp) + 1;
  92.     if (size > SIZE_MAX) {
  93.         /* should post an error here */
  94.         return NULL;
  95.     }
  96.  
  97.     if (dest == NULL)         /* allocate storage with room for null at end */
  98.     {
  99.         dest = Nlm_MemNew((size_t) size);
  100.         if (dest == NULL) return dest;
  101.     }
  102.  
  103.     tmp = (Nlm_BytePtr) dest;
  104.     bsup = bsp->chain;
  105.  
  106.     while (bsup != NULL)
  107.     {
  108.         from = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
  109.         Nlm_MemCopy(tmp, from, bsup->len);
  110.         Nlm_HandUnlock(bsup->str);
  111.         tmp += bsup->len;
  112.         bsup = bsup->next;
  113.     }
  114.  
  115.     return dest;
  116. }
  117.  
  118. /*****************************************************************************
  119. *
  120. *   ByteStorePtr Nlm_BSNew(len)
  121. *       creates a big enough bytestore for len
  122. *
  123. *****************************************************************************/
  124. Nlm_ByteStorePtr LIBCALL Nlm_BSNew (Nlm_Int4 len)
  125.  
  126. {
  127.     Nlm_ByteStorePtr bsp;
  128.     Nlm_Int4 added;
  129.  
  130.     bsp = (Nlm_ByteStorePtr) Nlm_MemNew(sizeof(ByteStore));
  131.     if (bsp == NULL)
  132.         return NULL;
  133.  
  134.     added = Nlm_BSAdd(bsp, len);
  135.     if (added < len)
  136.         bsp = Nlm_BSFree(bsp);
  137.     return bsp;
  138. }
  139.  
  140. /*****************************************************************************
  141. *
  142. *   Int4 BSAdd(bsp, len)
  143. *       adds len bytes BEFORE current bsp->seekptr
  144. *       bsp->seekptr returned pointing at first added byte
  145. *       returns bytes added
  146. *
  147. *****************************************************************************/
  148. Nlm_Int4 LIBCALL  Nlm_BSAdd (Nlm_ByteStorePtr bsp, Nlm_Int4 len)
  149.  
  150. {
  151.     Nlm_BSUnitPtr bsup,      /* current bsunit */
  152.                   ccbsup,    /* bsp->curchain */
  153.                 lastbsup,    /* bsunit after added section  */
  154.                 prevbsup;    /* bsunit before added section */
  155.     Nlm_BytePtr to, from;
  156.     Nlm_Int4 added = 0,
  157.               tlen;
  158.     Nlm_Handle thand;
  159.  
  160.     if ((bsp == NULL) || (len == 0))
  161.         return added;
  162.  
  163.     lastbsup = NULL;
  164.     prevbsup = NULL;
  165.     ccbsup = bsp->curchain;
  166.  
  167.     if (bsp->chain != NULL)        /* add or insert in exisiting chain */
  168.     {
  169.         if (bsp->seekptr == bsp->chain_offset)   /* before start of block */
  170.         {
  171.             lastbsup = ccbsup;       /* it comes after */
  172.             if (bsp->seekptr != 0)          /* something before it */
  173.             {
  174.                 prevbsup = bsp->chain;
  175.                 while (prevbsup->next != ccbsup)
  176.                     prevbsup = prevbsup->next;
  177.             }
  178.         }                                         /* after all blocks */
  179.         else if (bsp->seekptr >= (bsp->chain_offset + ccbsup->len_avail))
  180.         {
  181.             prevbsup = ccbsup;
  182.         }
  183.         else                /* split a bsunit */
  184.         {
  185.             bsup = (Nlm_BSUnitPtr) Nlm_MemNew(sizeof(Nlm_BSUnit));
  186.             if (bsup == NULL) return added;
  187.             if (bsp->chain_offset != 0)          /* not first BSUnit */
  188.             {
  189.                 prevbsup = bsp->chain;
  190.                 while (prevbsup->next != ccbsup)
  191.                     prevbsup = prevbsup->next;
  192.                 prevbsup->next = bsup;      /* insert new bsunit */
  193.             }
  194.             else
  195.                 bsp->chain = bsup;
  196.             bsup->next = ccbsup;
  197.             tlen = bsp->seekptr - bsp->chain_offset;  /* len of first half */
  198.             bsup->str = Nlm_HandNew((size_t) tlen);
  199.             if (bsup->str == NULL) return added;
  200.             bsup->len = (Nlm_Int2) tlen;
  201.             bsup->len_avail = (Nlm_Int2) tlen;
  202.             to = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
  203.             thand = ccbsup->str;
  204.             from = (Nlm_BytePtr) Nlm_HandLock(thand);
  205.             Nlm_MemCopy(to, from, (size_t) tlen);
  206. #ifdef MSC_VIRT
  207.             wrote_to_handle = TRUE;
  208. #endif
  209.             Nlm_HandUnlock(bsup->str);
  210.             from += tlen;      /* point past copied region */
  211.             tlen = ccbsup->len - tlen;    /* the last half */
  212.             ccbsup->len = (Nlm_Int2) tlen;
  213.             ccbsup->len_avail = (Nlm_Int2) tlen;
  214.             ccbsup->str = Nlm_HandNew((size_t) tlen);
  215.             if (ccbsup->str == NULL) return added;
  216.             to = (Nlm_BytePtr) Nlm_HandLock(ccbsup->str);
  217.             Nlm_MemCopy(to, from, (size_t) tlen);
  218. #ifdef MSC_VIRT
  219.     wrote_to_handle = TRUE;
  220. #endif
  221.             Nlm_HandUnlock(ccbsup->str);
  222.             Nlm_HandUnlock(thand);
  223.             Nlm_HandFree(thand);
  224.             prevbsup = bsup;
  225.             lastbsup = ccbsup;
  226.         }
  227.     }
  228.  
  229.     ccbsup = NULL;
  230.     bsup = NULL;
  231.     while (len)
  232.     {
  233.         bsup = (Nlm_BSUnitPtr) Nlm_MemNew(sizeof(Nlm_BSUnit));
  234.         if (bsup == NULL)
  235.             return added;
  236.         if (len < MAX_BSALLOC)
  237.             tlen = len;
  238.         else
  239.             tlen = MAX_BSALLOC;
  240.         bsup->str = Nlm_HandNew((size_t)tlen);
  241.         if (bsup->str == NULL)
  242.         {
  243.             Nlm_MemFree(bsup);
  244.             return added;
  245.         }
  246.         bsup->len_avail = (Nlm_Int2) tlen;
  247.         if (prevbsup == NULL)
  248.             bsp->chain = bsup;
  249.         else
  250.             prevbsup->next = bsup;
  251.         if (ccbsup == NULL)
  252.             ccbsup = bsup;          /* current position */
  253.         prevbsup = bsup;
  254.         len -= tlen;
  255.         added += tlen;
  256.     }
  257.     if (bsup != NULL)
  258.         bsup->next = lastbsup;
  259.     bsp->curchain = ccbsup;
  260.     bsp->chain_offset = bsp->seekptr;   /* added block starts at seekptr */
  261.     return added;
  262. }
  263.  
  264. /*****************************************************************************
  265. *
  266. *   Int4 BSDelete(bsp, len)
  267. *       deletes len bytes starting at current bsp->seekptr
  268. *       returns bytes deleted
  269. *
  270. *****************************************************************************/
  271. Nlm_Int4 LIBCALL  Nlm_BSDelete (Nlm_ByteStorePtr bsp, Nlm_Int4 len)
  272.  
  273. {
  274.     Nlm_BSUnitPtr bsup,      /* current bsunit */
  275.                   ccbsup,    /* bsp->curchain */
  276.                 nextbsup,    /* bsunit after added section  */
  277.                 prevbsup;    /* bsunit before added section */
  278.     Nlm_BytePtr to, from;
  279.     Nlm_Int4 added = 0,
  280.               offset,
  281.               tlen,
  282.               start,
  283.               save;
  284.     Nlm_Handle thand;
  285.  
  286.     if ((bsp == NULL) || (len == 0) || (bsp->chain == NULL) ||
  287.         (bsp->seekptr >= bsp->totlen))
  288.         return added;
  289.  
  290.     if ((bsp->seekptr + len) > bsp->totlen)   /* deleting too much */
  291.         len = bsp->totlen - bsp->seekptr;
  292.  
  293.     nextbsup = NULL;
  294.     ccbsup = bsp->curchain;
  295.     start = bsp->chain_offset;
  296.     offset = bsp->seekptr - bsp->chain_offset;
  297.     if (offset)           /* will leave part of first bsunit */
  298.         prevbsup = ccbsup;
  299.     else if (bsp->chain_offset != 0)          /* something before this bsunit */
  300.     {
  301.         prevbsup = bsp->chain;
  302.         while (prevbsup->next != ccbsup)
  303.             prevbsup = prevbsup->next;
  304.     }
  305.     else
  306.         prevbsup = NULL;       /* will remove beginning of first bsunit */
  307.  
  308.     bsup = ccbsup;
  309.     while (len)
  310.     {
  311.         nextbsup = bsup->next;
  312.         tlen = bsup->len - offset;
  313.         if (tlen > len)
  314.             tlen = len;             /* will remove tlen bytes from this BSUnit*/
  315.         save = bsup->len - tlen;
  316.         if (save)    /* some bytes left after delete */
  317.         {
  318.             thand = bsup->str;
  319.             bsup->str = Nlm_HandNew((size_t) save);
  320.             if (bsup->str == NULL) return added;
  321.             bsup->len = (Nlm_Int2) save;
  322.             bsup->len_avail = (Nlm_Int2) save;
  323.             to = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
  324.             from = (Nlm_BytePtr) Nlm_HandLock(thand);
  325.             if (offset)         /* get the beginning */
  326.                 Nlm_MemCopy(to, from, (size_t) offset);
  327.             save -= offset;
  328.             if (save)           /* save end */
  329.                 Nlm_MemCopy((to + offset), (from + (offset + tlen)), (size_t)save);
  330.             Nlm_HandUnlock(thand);
  331.             Nlm_HandFree(thand);
  332. #ifdef MSC_VIRT
  333.     wrote_to_handle = TRUE;
  334. #endif
  335.             Nlm_HandUnlock(bsup->str);
  336.             if (tlen < len)
  337.                 bsup = nextbsup;
  338.         }
  339.         else                    /* delete the whole thing */
  340.         {
  341.             Nlm_HandFree(bsup->str);
  342.             Nlm_MemFree(bsup);
  343.             bsup = nextbsup;
  344.         }
  345.         offset = 0;
  346.         len -= tlen;
  347.         added += tlen;
  348.     }
  349.     if (bsup != prevbsup)   /* break in chain, rejoin it */
  350.     {
  351.         if (prevbsup == NULL)
  352.             bsp->chain = bsup;
  353.         else
  354.             prevbsup->next = bsup;
  355.     }
  356.     bsp->curchain = bsup;
  357.     bsp->totlen -= added;
  358.     if (bsp->totlen)
  359.     {
  360.         offset = bsp->seekptr;
  361.         start = 0;
  362.         bsup = bsp->chain;
  363.         while (offset >= (start + bsup->len_avail))
  364.         {
  365.             if (bsup->next == NULL)    /* EOF */
  366.                 offset = 0;            /* stop loop */
  367.             else
  368.             {
  369.                 start += bsup->len;
  370.                 bsup = bsup->next;
  371.             }
  372.         }
  373.         bsp->curchain = bsup;
  374.         bsp->chain_offset = start;
  375.     }
  376.     else
  377.     {
  378.         bsp->chain_offset = 0;
  379.         bsp->curchain = bsp->chain;
  380.     }
  381.     return added;
  382. }
  383.  
  384. /*****************************************************************************
  385. *
  386. *   Nlm_Int4 Nlm_BSTell(bsp)
  387. *
  388. *****************************************************************************/
  389. Nlm_Int4 LIBCALL  Nlm_BSTell (Nlm_ByteStorePtr bsp)
  390.  
  391. {
  392.     if (bsp == NULL)
  393.         return 0L;
  394.  
  395.     return bsp->seekptr;
  396. }
  397.  
  398. /*****************************************************************************
  399. *
  400. *   Int2 Nlm_BSSeek(bsp, offset, origin)
  401. *       seeks as fseek()
  402. *       trys to lock a BSUnit at that seek position
  403. *
  404. *****************************************************************************/
  405. Nlm_Int2 LIBCALL  Nlm_BSSeek (Nlm_ByteStorePtr bsp, Nlm_Int4 offset, Nlm_Int2 origin)
  406.  
  407. {
  408.     Nlm_Int4 sp, start;
  409.     Nlm_BSUnitPtr bsup;
  410.     Nlm_Boolean done;
  411.  
  412.     if (bsp == NULL)
  413.         return 1;
  414.     if (bsp->chain == NULL)
  415.         return 1;
  416.  
  417.     sp = bsp->seekptr;
  418.  
  419.     switch (origin)
  420.     {
  421.         case SEEK_SET:
  422.             if ((offset > bsp->totlen) || (offset < 0))
  423.                 return 1;
  424.             sp = offset;
  425.             break;
  426.         case SEEK_CUR:
  427.             if (((sp + offset) > bsp->totlen) ||
  428.                 ((sp + offset) < 0 ))
  429.                 return 1;
  430.             sp += offset;
  431.             break;
  432.         case SEEK_END:
  433.             if ((ABS(offset) > bsp->totlen) || (offset > 0))
  434.                 return 1;
  435.             sp = bsp->totlen + offset;
  436.             break;
  437.         default:
  438.             return 1;
  439.     }
  440.  
  441.     if (sp == bsp->seekptr)     /* already in right position */
  442.         return 0;
  443.  
  444.     bsp->seekptr = sp;
  445.                                  /* if a valid seek, lock the right BSUnit */
  446.     bsup = bsp->curchain;
  447.  
  448.     if (sp == bsp->totlen)    /* seek to EOF */
  449.     {
  450.         if (sp > (bsp->chain_offset + bsup->len_avail))
  451.         {
  452.             start = bsp->chain_offset;
  453.             while (sp > (start + bsup->len_avail))
  454.             {
  455.                 start += bsup->len;
  456.                 bsup = bsup->next;
  457.             }
  458.         }
  459.     }
  460.     else if ((sp < bsp->chain_offset) ||
  461.         (sp >= (bsp->chain_offset + bsup->len)))
  462.     {
  463.         if (sp < bsp->chain_offset)
  464.         {
  465.             bsup = bsp->chain;
  466.             start = 0;
  467.         }
  468.         else
  469.         {
  470.             start = bsp->chain_offset + bsup->len;
  471.             bsup = bsup->next;
  472.         }
  473.         done = FALSE;
  474.         while (! done)
  475.         {
  476.             if ((start + bsup->len) > sp)
  477.                 done = TRUE;
  478.             else
  479.             {
  480.                 start += bsup->len;
  481.                 bsup = bsup->next;
  482.             }
  483.         }
  484.     }
  485.     if (bsup != bsp->curchain)
  486.     {
  487.         bsp->chain_offset = start;
  488.         bsp->curchain = bsup;
  489.     }
  490.     return 0;
  491. }
  492. /*****************************************************************************
  493. *
  494. *   Int4 Nlm_BSLen(bsp)
  495. *      gives cumulative length of strings in store (not counting \0)
  496. *
  497. *****************************************************************************/
  498. Nlm_Int4 LIBCALL  Nlm_BSLen (Nlm_ByteStorePtr bsp)
  499.  
  500. {
  501.     if (bsp == NULL)
  502.         return 0L;
  503.  
  504.     return bsp->totlen;
  505. }
  506.  
  507. /*****************************************************************************
  508. *
  509. *   Int2 BSPutByte(bsp, value)
  510. *       - returns value on success, EOF on failure
  511. *       - BSPutByte(bsp, EOF) truncates at seekptr
  512. *
  513. *****************************************************************************/
  514. Nlm_Int2 LIBCALL  Nlm_BSPutByte (Nlm_ByteStorePtr bsp, Nlm_Int2 value)
  515.  
  516. {
  517.     Nlm_Uint1 b;
  518.     if (value == EOF)
  519.         Nlm_BSDelete(bsp, INT4_MAX);
  520.     else {
  521.         b = (Nlm_Uint1) value;
  522.         if (Nlm_BSWrite(bsp, (Nlm_VoidPtr)&b, 1) == 0)
  523.             return EOF;
  524.     }
  525.     return value;
  526. }
  527.  
  528. /*****************************************************************************
  529. *
  530. *   Int4 BSWrite(bsp, ptr, len)
  531. *       returns bytes written from ptr to bsp
  532. *       writes from current seekptr position
  533. *       seekptr left pointing after last byte written
  534. *       allocates storage if needed
  535. *       writes over any data already there
  536. *
  537. *****************************************************************************/
  538. Nlm_Int4 LIBCALL  Nlm_BSWrite (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
  539.  
  540. {
  541.     Nlm_BytePtr from, to;
  542.     Nlm_BSUnitPtr bsup;
  543.     Nlm_Int4 tlen, added = 0, offset, start, diff;
  544.  
  545.     if ((bsp == NULL) || (len <= 0))
  546.         return added;
  547.  
  548.     bsup = bsp->curchain;
  549.     from = (Nlm_BytePtr) ptr;
  550.     offset = bsp->seekptr - bsp->chain_offset;
  551.     start = bsp->chain_offset;
  552.  
  553.      while (len)
  554.     {
  555.         if (bsup == NULL)
  556.             tlen = 0;
  557.         else
  558.             tlen = bsup->len_avail - offset;
  559.         if (len < tlen)
  560.             tlen = len;
  561.         if (! tlen)       /* out of space */
  562.         {
  563.             Nlm_BSAdd(bsp, len);
  564.             bsup = bsp->curchain;
  565.             offset = bsp->seekptr - bsp->chain_offset;
  566.             tlen = bsup->len_avail;
  567.         }
  568.         else
  569.         {
  570.             bsp->chain_offset = start;
  571.             bsp->curchain = bsup;
  572.         }
  573.         to = (Nlm_BytePtr)Nlm_HandLock(bsup->str) + offset;
  574.         Nlm_MemCopy(to, from, (size_t) tlen);
  575. #ifdef MSC_VIRT
  576.     wrote_to_handle = TRUE;
  577. #endif
  578.         Nlm_HandUnlock(bsup->str);
  579.         if (bsup->len < (Nlm_Int2)(tlen + offset))   /* added more to this bsunit */
  580.         {
  581.             diff = (tlen + offset) - bsup->len;
  582.             bsp->totlen += diff;
  583.             bsup->len += (Nlm_Int2) diff;
  584.         }
  585.         offset = 0;        /* only offset on first one */
  586.         len -= tlen;
  587.         bsp->seekptr += tlen;
  588.         start += bsup->len;
  589.         added += tlen;
  590.         from += tlen;
  591.         if (len)
  592.             bsup = bsup->next;
  593.     }
  594.                      /* pointing past end of this BSunit */
  595.  
  596.     if ((bsp->seekptr - bsp->chain_offset) >= bsup->len_avail)
  597.     {
  598.         if (bsup->next != NULL)      /* not end of space */
  599.         {
  600.             bsp->curchain = bsup->next;
  601.             bsp->chain_offset += bsup->len;  /* should = len_avail */
  602.         }
  603.     }
  604.     return added;
  605. }
  606. /*****************************************************************************
  607. *
  608. *   Int4 BSRead(bsp, ptr, len)
  609. *       returns bytes read from bsp to ptr
  610. *       reads from current seekptr position
  611. *       seekptr left pointing after last byte read
  612. *
  613. *****************************************************************************/
  614. Nlm_Int4 LIBCALL  Nlm_BSRead (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
  615.  
  616. {
  617.     Nlm_BytePtr from, to;
  618.     Nlm_BSUnitPtr bsup;
  619.     Nlm_Int4 tlen, added = 0, offset, start;
  620.  
  621.     if ((bsp == NULL) || (len <= 0))
  622.         return added;
  623.  
  624.     bsup = bsp->curchain;
  625.     to = (Nlm_BytePtr) ptr;
  626.     offset = bsp->seekptr - bsp->chain_offset;
  627.     start = bsp->chain_offset;
  628.  
  629.      while (len)
  630.     {
  631.         if (bsup == NULL)
  632.             return added;
  633.         tlen = bsup->len - offset;
  634.         if (len < tlen)
  635.             tlen = len;
  636.         if (! tlen)       /* out of data */
  637.             return added;
  638.         bsp->chain_offset = start;
  639.         from = (Nlm_BytePtr)Nlm_HandLock(bsup->str) + offset;
  640.         Nlm_MemCopy(to, from, (size_t) tlen);
  641.         Nlm_HandUnlock(bsup->str);
  642.         offset = 0;        /* only offset on first one */
  643.         len -= tlen;
  644.         bsp->seekptr += tlen;
  645.         bsp->curchain = bsup;
  646.         start += bsup->len;
  647.         added += tlen;
  648.         to += tlen;
  649.         if (len)
  650.             bsup = bsup->next;
  651.     }                                    /*** end of this bsunit? **/
  652.     if ((bsp->seekptr - bsp->chain_offset) == bsup->len)
  653.     {
  654.         if (bsp->seekptr != bsp->totlen)    /* not EOF */
  655.         {
  656.             bsp->curchain = bsup->next;
  657.             bsp->chain_offset += bsup->len;
  658.         }
  659.     }
  660.     return added;
  661. }
  662.  
  663. /*****************************************************************************
  664. *
  665. *   Int2 BSGetByte(bsp)
  666. *      reads a byte and increments the seekptr
  667. *      returns EOF on End-Of-BS or error
  668. *
  669. *****************************************************************************/
  670. Nlm_Int2 LIBCALL  Nlm_BSGetByte (Nlm_ByteStorePtr bsp)
  671.  
  672. {
  673.     Nlm_Int2 retval;
  674.     Nlm_BytePtr ptr;
  675.     Nlm_Int4 diff;
  676.     Nlm_BSUnitPtr bsup;
  677.  
  678.     if ((bsp == NULL) || (bsp->totlen == 0) || (bsp->seekptr == bsp->totlen))
  679.         return EOF;      /* EOF */
  680.  
  681.     diff = bsp->seekptr - bsp->chain_offset;
  682.     bsup = bsp->curchain;
  683.     ptr = (Nlm_BytePtr) Nlm_HandLock(bsup->str);
  684.     retval = (Nlm_Int2) *(ptr + diff);
  685.     Nlm_HandUnlock(bsup->str);
  686.  
  687.     bsp->seekptr++;
  688.     diff++;
  689.     if (diff == bsup->len)
  690.     {
  691.         if (bsp->seekptr != bsp->totlen)    /* not EOF */
  692.         {
  693.             bsp->curchain = bsup->next;
  694.             bsp->chain_offset += bsup->len;
  695.         }
  696.     }
  697.     return retval;    
  698. }
  699.  
  700. /*****************************************************************************
  701. *
  702. *   Int4 BSInsert(bsp, ptr, len)
  703. *       returns bytes written from ptr into bsp
  704. *       writes from current seekptr position
  705. *       seekptr left pointing after last byte written
  706. *       allocates storage if needed
  707. *       inserts data BEFORE seekptr
  708. *
  709. *****************************************************************************/
  710. Nlm_Int4 LIBCALL  Nlm_BSInsert (Nlm_ByteStorePtr bsp, Nlm_VoidPtr ptr, Nlm_Int4 len)
  711.  
  712. {
  713.     Nlm_Int4 added;
  714.  
  715.     added = Nlm_BSAdd(bsp, len);
  716.     if (added != len)
  717.     {
  718.         Nlm_BSDelete(bsp, added);
  719.         return 0;
  720.     }
  721.     added = Nlm_BSWrite(bsp, ptr, len);
  722.     return added;
  723. }
  724.  
  725. /*****************************************************************************
  726. *
  727. *   Int4 BSInsertFromBS(bsp, bsp2, len)
  728. *       returns bytes written from bsp2 into bsp
  729. *       reads from bsp2 starting from current seek position
  730. *       writes from current seekptr position
  731. *       seekptr left pointing after last byte written
  732. *       allocates storage if needed
  733. *       inserts data BEFORE seekptr
  734. *
  735. *****************************************************************************/
  736. Nlm_Int4 LIBCALL  Nlm_BSInsertFromBS (Nlm_ByteStorePtr bsp, Nlm_ByteStorePtr bsp2, Nlm_Int4 len)
  737. {
  738.     Nlm_Int4 added;
  739.     Nlm_Int2 x;
  740.  
  741.     added = Nlm_BSAdd(bsp, len);
  742.     if (added != len)
  743.     {
  744.         Nlm_BSDelete(bsp, added);
  745.         return 0;
  746.     }
  747.  
  748.     for (added = 0; added < len; added++)
  749.     {
  750.         x = Nlm_BSGetByte(bsp2);
  751.         Nlm_BSPutByte(bsp, x);
  752.     }
  753.     return added;
  754. }
  755.  
  756. /*****************************************************************************
  757. *
  758. *   ByteStorePtr Nlm_BSFree(bsp)
  759. *
  760. *****************************************************************************/
  761. Nlm_ByteStorePtr LIBCALL  Nlm_BSFree (Nlm_ByteStorePtr bsp)
  762.  
  763. {
  764.     Nlm_BSUnitPtr bsup, tmp;
  765.  
  766.     if (bsp == NULL)
  767.         return NULL;
  768.         
  769.     bsup = bsp->chain;
  770.     while (bsup != NULL)
  771.     {
  772.         tmp = bsup;
  773.         bsup = bsup->next;
  774.         Nlm_HandFree(tmp->str);
  775.         Nlm_MemFree(tmp);
  776.     }
  777.     return (Nlm_ByteStorePtr) Nlm_MemFree(bsp);
  778. }
  779.  
  780. Nlm_ByteStorePtr LIBCALL Nlm_BSDup(Nlm_ByteStorePtr source)
  781. {
  782.     Nlm_ByteStorePtr dest;
  783.     Nlm_Int4 sourceLen;
  784.     Nlm_Int4 sourceLoc;
  785.     Nlm_Int4 added;
  786.  
  787.     if (source == NULL)
  788.     {
  789.         return NULL;
  790.     }
  791.     sourceLen = Nlm_BSLen(source);
  792.     dest = Nlm_BSNew(0);
  793.     /* read the original location */
  794.     sourceLoc = Nlm_BSTell(source);
  795.     Nlm_BSSeek(source, 0, SEEK_SET);
  796.     added = Nlm_BSInsertFromBS(dest, source, sourceLen);
  797.     /* restore original location */
  798.     Nlm_BSSeek(source, sourceLoc, SEEK_SET);
  799.     if (added != sourceLen)
  800.     {
  801.         Nlm_BSFree(dest);
  802.         return NULL;
  803.     }
  804.     /* for neatness, make the duplicate point to the same location as the
  805.        old one */
  806.     Nlm_BSSeek(dest, sourceLoc, SEEK_SET);
  807.     return dest;
  808. }
  809.